import { deepClone } from "@/plugins/utils";
const SVGNS = "http://www.w3.org/2000/svg";

export default class MarkCanvas {
  constructor(parentEle, elements, registerDeleteFunc) {
    this.canvasBox = parentEle; // 当前canvas父级dom
    this.svgElement = this.initSVG(); // 初始化canvas
    this.cacheElements = []; // 缓存关系数据
    if (Array.isArray(elements) && elements.length) {
      // 初始化时是否需要回显关系图
      this.cacheElements = elements;
      this.initRelations();
    }
    this.deleteCallback = registerDeleteFunc;
  }
  // 初始化svg
  initSVG() {
    const canvasWidth = this.canvasBox.offsetWidth;
    const canvasHeight = this.canvasBox.offsetHeight;
    const svgElement = document.createElementNS(SVGNS, "svg");
    svgElement.setAttribute("xmlns", SVGNS);
    svgElement.setAttribute("version", "1.1");
    svgElement.setAttribute("width", canvasWidth);
    svgElement.setAttribute("height", canvasHeight);
    svgElement.style.width = `${canvasWidth}px`;
    svgElement.style.height = `${canvasHeight}px`;
    svgElement.style.position = `absolute`;
    svgElement.style.top = `0`;
    svgElement.style.left = `0`;

    const defs = document.createElementNS(SVGNS, "defs");
    const markerArrow = document.createElementNS(SVGNS, "path");
    markerArrow.setAttribute("d", "M0,4 L0,8 L6,6 L0,4 L0,8");
    markerArrow.setAttribute("stroke", "#000000");
    markerArrow.setAttribute("fill", "#000000");
    const markerElement = document.createElementNS(SVGNS, "marker");
    markerElement.setAttribute("id", "marker-arrow");
    markerElement.setAttribute("markerWidth", "8");
    markerElement.setAttribute("markerHeight", "10");
    markerElement.setAttribute("orient", "auto");
    markerElement.setAttribute("refX", "5");
    markerElement.setAttribute("refY", "6");
    markerElement.appendChild(markerArrow);
    defs.appendChild(markerElement);
    svgElement.appendChild(defs);

    this.canvasBox.appendChild(svgElement);
    return svgElement;
  }
  // 给父级元素添加事件，鼠标移入时以编辑为主，鼠标移出时以显示关系为主
  bindHandleForParent() {
    // 光标移入时降低canvas层级用来编辑html
    this.canvasBox.addEventListener("mouseenter", () => {
      // console.log('mouseenter')
      this.canvas.style.zIndex = -1;
    });
    // 光标移出时提高canvas层级用来显示关系
    this.canvasBox.addEventListener("mouseleave", () => {
      this.canvas.style.zIndex = 1;
    });
  }
  // 初始化回显关系
  initRelations() {
    let startTime = new Date().getTime();
    this.resize();

    const newSVG = this.svgElement.cloneNode(false);
    this.svgElement.parentNode.replaceChild(newSVG, this.svgElement);
    this.svgElement = newSVG;

    const defs = document.createElementNS(SVGNS, "defs");
    const markerArrow = document.createElementNS(SVGNS, "path");
    markerArrow.setAttribute("d", "M0,4 L0,8 L6,6 L0,4 L0,8");
    markerArrow.setAttribute("stroke", "#000000");
    markerArrow.setAttribute("fill", "#000000");
    const markerElement = document.createElementNS(SVGNS, "marker");
    markerElement.setAttribute("id", "marker-arrow");
    markerElement.setAttribute("markerWidth", "8");
    markerElement.setAttribute("markerHeight", "10");
    markerElement.setAttribute("orient", "auto");
    markerElement.setAttribute("refX", "5");
    markerElement.setAttribute("refY", "6");
    markerElement.appendChild(markerArrow);
    defs.appendChild(markerElement);
    this.svgElement.appendChild(defs);
    const svgElements = this.cacheElements.map(
      this.generateElements.bind(this)
    );

    this.svgElement.append(...svgElements);
    console.log(`初始化关系图耗时：${new Date().getTime() - startTime}ms`);
  }
  // 创建关系
  createRelation(element) {
    let isExist = this.cacheElements.find((ele) => {
      return ele.id === element.id;
    });
    if (!isExist) {
      this.cacheElements.push(element);
      this.initRelations();
    }
  }
  // 删除关系
  deleteRelation(id) {
    let delIndex = this.cacheElements.findIndex((ele) => {
      return ele.id === id;
    });
    let delElement = deepClone(this.cacheElements[delIndex]);
    this.cacheElements.splice(delIndex, 1);
    this.initRelations();
    this.deleteTag(id);
    this.deleteCallback(delElement);
  }
  deleteTag(id) {
    let delTag = document.getElementById(id);
    if (delTag) {
      this.canvasBox.removeChild(delTag);
    }
  }
  // 根据元素进行绘制
  generateElements(element) {
    element = this.reConfigElement(element);
    let { path, relationEle } = element;
    this.plainRelation(path, relationEle);

    return this.generateSVGElement(path);
  }
  // 绘制线
  generateSVGElement(path) {
    let pathElement = document.createElementNS(SVGNS, "path");

    const svgPath = `
    M ${path[0][0]}   ${path[0][1]}
    L ${path[1][0]} ${path[1][1]}
    L ${path[2][0]} ${path[2][1]}
    L ${path[3][0]} ${path[3][1] - 3}
`;
    pathElement.setAttribute("d", svgPath);
    pathElement.setAttribute("fill", "none");
    pathElement.setAttribute("stroke", "#000000");
    pathElement.setAttribute("stroke-width", "1");
    pathElement.setAttribute("stroke-width", "1");
    pathElement.style.markerEnd = "url(#marker-arrow)";

    return pathElement;
  }
  // 绘制关系
  plainRelation(path, relationEle) {
    let x =
      Math.min(path[2][0], path[1][0]) + Math.abs(path[2][0] - path[1][0]) / 2; // 关系标签中心点x坐标
    let y = path[1][1];
    this.calculateRelationEleSize(relationEle, { x, y });
    relationEle.style.visibility = "visible";
  }
  // 给element添加path和关系标签
  reConfigElement(element) {
    // step 根据当前实体对应的标签个数及标签的高度计算
    let { startElement, endElement, id, relation, step } = element;
    let startEle = document.getElementById(startElement);
    let endEle = document.getElementById(endElement);

    let startEleConfig = this.getElementOffset(startEle); // {left,top,width,topCenterX,topCenterY}
    let endEleConfig = this.getElementOffset(endEle);
    startEleConfig.width = startEle.offsetWidth; // 头实体标签的宽
    startEleConfig.topCenterX = startEleConfig.left + startEleConfig.width / 2; // 起始点x
    startEleConfig.topCenterY = startEleConfig.top; // 起始点y
    startEleConfig.right = startEleConfig.left + startEleConfig.width; // 头实体右上角x

    endEleConfig.width = endEle.offsetWidth; // 尾实体标签的宽
    // 上部中心点
    endEleConfig.topCenterX = endEleConfig.left + endEleConfig.width / 2; // 终点x
    endEleConfig.topCenterY = endEleConfig.top; // 终点y
    endEleConfig.right = endEleConfig.left + endEleConfig.width; // 尾实体右上角x

    let relationEle = this.createRelationTag(id, relation); // 关系标签中心点y坐标

    let relationEleWidth = relationEle.offsetWidth; //

    // var path;
    const offset = 10;
    const padding = 10;
    let path,
      move_to_x,
      move_to_y,
      path_1_x,
      path_1_y,
      path_2_x,
      path_2_y,
      path_3_x,
      path_3_y,
      originToTargetWidth;
    // 右侧指向左侧
    if (startEleConfig.topCenterX >= endEleConfig.topCenterX) {
      move_to_x = startEleConfig.right;
      move_to_y = startEleConfig.top;
      path_3_x = endEleConfig.left;
      path_3_y = endEleConfig.top;
      originToTargetWidth = Math.abs(move_to_x - path_3_x); // 两个标签最大间距
      if (originToTargetWidth + offset * 2 - relationEleWidth >= padding * 2) {
        // 两个标签间距能够包含关系标签长度
        path_1_x = move_to_x + offset;
        path_1_y =
          Math.min(startEleConfig.topCenterY, endEleConfig.topCenterY) - step;
        path_2_x = path_3_x - offset;
        path_2_y = path_1_y;
      } else {
        let path_2_length = relationEleWidth + padding * 2;
        // 默认向右偏
        path_1_y =
          Math.min(startEleConfig.topCenterY, endEleConfig.topCenterY) - step;
        path_2_x = path_3_x - offset;
        path_2_y = path_1_y;
        path_1_x = path_2_x + path_2_length;
        if (path_1_x > this.canvasBox.offsetWidth) {
          // 向右偏会超出文本
          path_1_x = move_to_x + offset;
          path_1_y =
            Math.min(startEleConfig.topCenterY, endEleConfig.topCenterY) - step;
          path_2_x = path_1_x - path_2_length;
          path_2_y = path_1_y;
        }
      }
    } else {
      // console.log('右侧指向左侧')
      move_to_x = startEleConfig.left;
      move_to_y = startEleConfig.top;
      path_3_x = endEleConfig.right;
      path_3_y = endEleConfig.top;
      originToTargetWidth = Math.abs(move_to_x - path_3_x);
      if (originToTargetWidth + offset * 2 - relationEleWidth >= padding * 2) {
        // 两个标签间距能够包含关系标签长度
        path_1_x = move_to_x - offset;
        path_1_y =
          Math.min(startEleConfig.topCenterY, endEleConfig.topCenterY) - step;
        path_2_x = path_3_x + offset;
        path_2_y = path_1_y;
      } else {
        let path_2_length = relationEleWidth + padding * 2;
        // 默认向左偏
        path_1_y =
          Math.min(startEleConfig.topCenterY, endEleConfig.topCenterY) - step;
        path_2_x = path_3_x + offset;
        path_2_y = path_1_y;
        path_1_x = path_2_x - path_2_length;
        if (path_1_x < 0) {
          // 向左偏会超出文本
          path_1_x = move_to_x - offset;
          path_1_y =
            Math.min(startEleConfig.topCenterY, endEleConfig.topCenterY) - step;
          path_2_x = path_1_x + path_2_length;
          path_2_y = path_1_y;
        }
      }
    }

    path = [
      [move_to_x, move_to_y],
      [path_1_x, path_1_y],
      [path_2_x, path_2_y],
      [path_3_x, path_3_y],
    ];

    element.startEleConfig = startEleConfig;
    element.endEleConfig = endEleConfig;
    element.path = path;
    element.relationEle = relationEle;
    // console.log(element);
    return element;
  }

  // 创建标签
  createRelationTag(id, value) {
    let relationEle = document.getElementById(id);
    if (relationEle) {
      return relationEle;
    }
    relationEle = document.createElement("div");
    relationEle.innerHTML = value;
    relationEle.setAttribute("labelName", value);
    relationEle.id = id;
    relationEle.className = "relationLabel";
    relationEle.style.position = "absolute";
    relationEle.style.fontSize = "12px";
    relationEle.style.visibility = "hidden";
    relationEle.style.zIndex = "1001";
    this.canvasBox.appendChild(relationEle);
    // 右键点击删除
    // relationEle.addEventListener("contextmenu", (ev) => {
    //   ev.preventDefault();
    //   let id = ev.target.id;
    //   this.deleteRelation(id);
    // });

    return relationEle;
  }
  calculateRelationEleSize(relationEle, center) {
    let eleWidth = relationEle.offsetWidth;
    let eleHeight = relationEle.offsetHeight;
    relationEle.style.left = `${center.x - eleWidth / 2}px`;
    relationEle.style.top = `${center.y - eleHeight / 2}px`;
  }
  getElementOffset(curEle) {
    let totalTop = curEle.offsetTop;
    let totalLeft = curEle.offsetLeft;
    let par = curEle.offsetParent;

    //现在开始一级一级往上查找，只要没有遇到body，我们就把父级参照物的边框和偏移相加
    while (par) {
      // 判定最外层元素是否是富文本编辑框内部某个元素
      if (par === this.canvasBox) {
        break;
      }
      totalTop += par.clientTop + par.offsetTop;
      totalLeft += par.clientLeft + par.offsetLeft;
      par = par.offsetParent;
    }
    return { left: totalLeft, top: totalTop };
  }
  resize() {
    const canvasWidth = this.canvasBox.offsetWidth;
    const canvasHeight = this.canvasBox.offsetHeight;

    this.svgElement.setAttribute("width", canvasWidth);
    this.svgElement.setAttribute("height", canvasHeight);

    this.svgElement.style.width = `${canvasWidth}px`;
    this.svgElement.style.height = `${canvasHeight}px`;
  }
  // 删除所有关系标签
  clear() {
    document.querySelectorAll(".relationLabel").forEach((ele) => {
      ele.remove();
    });
  }
}
